"""
消息处理类
"""
from warnings import warn
from bdtime import tt
from .msg_class import *
from random import randint
from concurrent.futures import ThreadPoolExecutor


encoding = 'utf-8'


class BaseState:
    agent_pos = None
    destination_pos = None
    reward = None
    done = None
    info = None

    def __init__(self, state_str):
        msg_dc = json.loads(state_str)
        for key, value in msg_dc.items():
            if key in self.__dir__():
                setattr(self, key, value)

    def __str__(self):
        return f'{self.__dict__}'

    def __repr__(self):
        return self.__str__()

    def to_string(self):
        return json.dumps(self.__dict__)


class EnvCli:
    @staticmethod
    def choose_action(msg_state):
        state_str = msg_state.state
        state_cls = BaseState(state_str)

        action = randint(0, 4)  # [0~4] 分别对应 [停, 上, 下, 左, 右]
        return action


class MsgHandle:
    executor = ThreadPoolExecutor(max_workers=3)

    def __init__(self, client_connection=None):
        self.client_connection = client_connection
        self.msg_listeners = {}
        self.use_executor = True

    def add_listener(self, key, method):
        if key in self.msg_listeners:
            self.msg_listeners[key] += [method]
        else:
            self.msg_listeners[key] = [method]

    def remove_listener(self, key, method):
        if key in self.msg_listeners:
            self.msg_listeners[key].remove(method)
        else:
            raise ValueError(f"method[{method}] not in msg_listeners")

    def send(self, msg):
        """
        对指定的client发送消息

        - msg_str: 可以为`str`类型, 也可以`MsgBase`和`bytes`
        """
        # print(f"--- on MsgHandle.send ---[{msg_str}]")
        if isinstance(msg, MsgBase):
            msg = MsgBase.encode(msg)
        elif isinstance(msg, dict):
            msg = json.dumps(msg)

        if isinstance(msg, str):
            msg_bytes = msg.encode(encoding)
        else:
            msg_bytes = msg
        # self.client_connection.send(msg_bytes)
        MessageController.send_message(self.client_connection, msg_bytes)

    def run(self, msg_str, use_executor=None):
        if isinstance(msg_str, bytes):
            msg_str = msg_str.decode(encoding)

        # print(f'--- on MsgHandle.run --- now: {tt.get_current_beijing_time_str(decimal_places=0)}')

        # msg_str = '{"protoName": "MsgAttack", "x": 100, "y": -20, "z": 0}'

        if isinstance(msg_str, dict):
            msg_dc = msg_str
        else:
            try:
                msg_dc = json.loads(msg_str)
            except Exception as e:
                raise TypeError(f'--- msg_str转json报错! msg_str: \n{msg_str} \n error: {e}')

        proto_name = msg_dc.get('protoName')
        if proto_name in self.msg_listeners:
            # print('--- in msg listeners!')
            method_ls = self.msg_listeners.get(proto_name)

            use_executor = use_executor if use_executor is not None else self.use_executor
            for method_i in method_ls:

                # 传dc
                if use_executor:
                    self.executor.submit(method_i, msg_dc)
                else:
                    method_i(msg_dc)

                # # 传str
                # method_i(msg_str)

                # # 传class
                # from net import msg_class
                # msg_cls = getattr(msg_class, proto_name)
                # obj = msg_cls()
                # obj.load(msg_str)
                # method_i(obj)
            return

        assert hasattr(self, proto_name), f'`{proto_name}`在MsgHandle中没有对应的消息处理方案!'
        method = getattr(self, proto_name)
        method(msg_str)

    def MsgTest(self, msg_str):
        print(f"--- on MsgHandle.MsgTest")
        assert isinstance(msg_str, str), '必须传入str类型!'
        my_msg = MsgTest(msg_str)
        print('~~~ my_msg: ', my_msg)
        self.send(my_msg.to_string())

    def MsgState(self, msg_str):
        # print(f"--- on MsgHandle.MsgState")
        if isinstance(msg_str, MsgBase):
            msg_str = MsgBase.encode(msg_str)
        assert isinstance(msg_str, str), '必须传入str类型!'

        msg_state = MsgState(msg_str)

        # action = EnvCli.choose_action(msg_state)
        # my_msg = MsgAction(action)

        my_msg = msg_state
        # print(f'~~~ tt[{tt.get_current_beijing_time_str(decimal_places=2)}] --- my_msg: {my_msg}')
        # print(f'--- my_msg: {my_msg}')
        self.send(my_msg.to_string())

    # region 测试用
    def MsgReset(self, msg_str):
        print(f"--- on MsgHandle.MsgReset")
        if isinstance(msg_str, MsgBase):
            msg_str = MsgBase.encode(msg_str)
        assert isinstance(msg_str, str), '必须传入str类型!'
        my_msg = MsgReset(msg_str)
        print('~~~ my_msg: ', my_msg)
        self.send(my_msg.to_string())

    def MsgMove(self, msg_str):
        print(f"--- on MsgHandle.MsgMove")
        assert isinstance(msg_str, str), '必须传入str类型!'
        msg_move = MsgMove(msg_str)
        print('~~~ msg_move: ', msg_move)
        self.send(msg_move.to_string())

    def MsgAttack(self, msg_str):
        print(f"--- on MsgHandle.MsgAttack")
        assert isinstance(msg_str, str), '必须传入str类型!'

        msg_attack = MsgAttack(msg_str)
        print(f'对[{msg_attack.target}]发动了攻击! 攻击描述: [{msg_attack.desc}]')
        print('~~~ msg_attack: ', msg_attack)

        msg_attack.desc = msg_attack.desc + '--->处理了[desc]'
        msg_attack.target = msg_attack.target + '--->处理了[target]'
        ret_str = msg_attack.to_string()
        # msg_attack.__dict__
        # json.dumps(msg_attack.__dict__)
        self.send(ret_str)

    def MsgClose(self, msg_str=None):
        print(f"--- on MsgHandle.MsgClose")
        # assert isinstance(msg_str, str), '必须传入str类型!'
        # msg_move = MsgMove(msg_str)
        msg = MsgClose()
        self.send(msg)
        MessageController.close(self.client_connection)
        self.client_connection = None
        # self.send(msg_move.to_string())

    def close(self):
        self.MsgClose()

    # endregion


msg_handle = MsgHandle()


import struct


# pack_format = "<I"  # 小端, Int
# recv_length = 4


pack_format = "<H"  # 小端, Short
recv_length = 2


class MessageController:
    @staticmethod
    def close(sock):
        if sock:
            sock.close()

    @staticmethod
    def recv_message(sock):
        if not sock or sock.fileno() == -1:
            return None
        # 先读取 4 字节的消息长度信息
        try:
            message_length_bytes = sock.recv(recv_length)
        except Exception as e:
            print("\n\n****** message_length_bytes error!")
            print(e)
        # num = int.from_bytes(message_length_bytes, byteorder='big', signed=True)
        # message_length_bytes.decode(encoding)

        if not message_length_bytes:
            return message_length_bytes

        # 将字节序列解包成整数
        message_length = struct.unpack(pack_format, message_length_bytes)[0]
        # 读取指定长度的消息体
        message = sock.recv(message_length)

        # print(f'--- recv_message | message_length --- {message_length}')
        return message

    @staticmethod
    def send_message(sock, message):
        # 将消息长度打包成 4 字节的字节序列
        message_length = struct.pack(pack_format, len(message))
        # 将消息长度和消息体拼接起来发送出去
        try:
            sock.send(message_length + message)
            # print(f'*** sock.getpeername[{sock.getpeername()}] --- sock.getsockname[{sock.getsockname()}]')
        except Exception as e:
            print(f'可能已关闭链接! error: {e}')




